<template>
  <div class="main">
    <div v-if="history_messages.length != 0" ref="scrollContainer" class="chat">
      <div v-for="(item, index) in history_messages" :key="index" class="chatList">
        <div v-if="item.role == 'user'" class="wen">
          <span class="content">{{ item.content[0].text }}</span>
        </div>
        <div v-if="item.role == 'assistant'" ref="da" class="da">
          <span ref="parsedMarkdown" class="content" v-html="item.content" />
          <div class="operation">
            <i class="el-icon-copy-document" @click="copy(item.content)" />
          </div>
        </div>
      </div>
    </div>

    <!-- 输入框 -->
    <div class="chat-input" :class="history_messages.length == 0 ? 'suspension' : ''">
      <textarea v-model="text" placeholder="请输入要查询的内容" @keyup.enter="fetchSSEData" />
      <div class="btn">
        <!-- 添加新对话 -->
        <el-button type="primary" round @click="addNewDialogue">
          <i class="el-icon-plus" />
          新对话
        </el-button>

        <!-- 发送消息 -->
        <el-button type="success" circle @click="fetchSSEData">
          <i v-if="!isShowLoading" class="el-icon-s-promotion" />
          <i v-else class="el-icon-loading" />
        </el-button>
      </div>
    </div>
  </div>
</template>

<script>
import showdown from "showdown";
import hljs from "highlight.js";
import "highlight.js/styles/default.css"; // 引入highlight.js的默认样式
import { getHistory, getUuid, saveHistory } from "@/api/openAi";
// import { v4 as uuidv4 } from "uuid";

export default {
  data() {
    return {
      messages: [],
      markdownText: "",
      parsedMarkdown: "",
      text: "",
      active: "/api/api/douBao",
      history_messages: [],
      history_id: "",
      sessionId: "",
      isShowLoading: false,
      userInfo: JSON.parse(sessionStorage.getItem("userInfo")) || {},
    };
  },

  mounted() {
    console.log(this.$route.query);
    this.connectWebSocket();

    if (this.$route.query.sessionId) {
      this.sessionId = this.$route.query.sessionId;
      this.getHistoryMessage();
    } else {
      this.addNewDialogue(false);
    }
  },

  beforeDestroy() {
    this.$closeWebSocket();
  },

  methods: {
    // 查询历史对话记录
    async getHistoryMessage() {
      try {
        const result = await getHistory({ sessionId: this.sessionId });
        if (result.code == 20000) {
          console.log(result, "result");
          this.history_messages = result.data.messages || [];
          this.history_id = result.data.id;
          this.highlightCode();
          this.setScrollToBottom();
        } else {
          this.$message.error(result.msg);
        }
      } catch (error) {
        this.$message.error(error);
      }
    },

    // 添加新对话
    async addNewDialogue(flag = true) {
      if (flag) {
        if (this.history_messages.length == 0) {
          this.$message.warning("当前已是最新对话");
          return;
        }
      }
      this.text = "";
      this.sessionId = (await getUuid({})).data;
      // this.sessionId = "cbf61051-35ec-44a9-af4f-87d42168662f";
      this.getHistoryMessage(); // 获取数据
    },

    // 发送问题
    async fetchSSEData() {
      if (this.isShowLoading) return;

      if (!this.text) {
        this.$message.warning("请输入要查询的内容");
        return;
      }

      this.history_messages.push({
        role: "user", // 用户角色
        content: [{ type: "text", text: this.text }],
      });
      this.isShowLoading = true;
      try {
        const parmse = {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            // 请求头
            "token": this.userInfo.token,
          },
          body: JSON.stringify({
            text: this.text, // 提问内容
            sessionId: this.sessionId, // 对话id
            messages: this.history_messages, // 对话记录
            id: this.history_id, // 数据id
            userId: this.userInfo.id || "",
          }),
        };

        this.history_messages.push({
          role: "assistant",
          content: "你等会儿，何东东正在思考...",
        });

        this.setScrollToBottom();
        this.text = "";

        // 开始请求数据
        const response = await fetch(this.active, parmse);

        // 判断是否请求失败
        if (!response.ok) {
          this.$message.error("请求失败： " + response.status);
          return;
        }

        // 解析数据流
        const reader = response.body.getReader();
        let done = false;

        while (!done) {
          const { done: readerDone } = await reader.read();
          done = readerDone;
        }

        // 保存对话记录
        await saveHistory({
          sessionId: this.sessionId,
          modelType: "豆包大模型",
          id: this.history_id,
          messages: this.history_messages,
        });
        this.markdownText = "";
        this.isShowLoading = false;
      } catch (error) {
        this.$message.error("请求失败： " + error.message);
        this.isShowLoading = false;
      }
    },

    // 处理代码高亮
    highlightCode(flag) {
      this.$nextTick(() => {
        const parsedMarkdowns = this.$refs.parsedMarkdown;
        if (!parsedMarkdowns) return;
        if (flag) {
          // 获取最后一个ai回答问题的索引
          let count = 0;
          this.history_messages.forEach((item) => {
            if (item.role == "assistant") {
              count++;
            }
          });

          parsedMarkdowns[count - 1]
            .querySelectorAll("pre code")
            .forEach((block) => {
              hljs.highlightBlock(block);
              this.addCopyButton(block); // 代码块儿右上角添加复制按钮
            });
        } else {
          parsedMarkdowns.forEach((item) => {
            item.querySelectorAll("pre code").forEach((block) => {
              hljs.highlightBlock(block);
              this.addCopyButton(block); // 代码块儿右上角添加复制按钮
            });
          });
        }
      });
    },

    // 代码块儿右上角添加复制按钮
    addCopyButton(codeBlock) {
      const preElement = codeBlock.parentNode;

      // 创建复制按钮
      const copyButton = document.createElement("button");
      copyButton.innerHTML = "<i class='el-icon-copy-document'></i>";
      copyButton.classList.add("copy-button");
      // 为复制按钮添加点击事件
      copyButton.addEventListener("click", async () => {
        this.copy(preElement.innerText, false);
      });
      // 设置按钮样式使其显示在右上角
      preElement.style.position = "relative";
      copyButton.style.position = "absolute";
      copyButton.style.top = "5px";
      copyButton.style.right = "5px";
      copyButton.style.backgroundColor = "#f0f0f0";
      copyButton.style.border = "1px solid #ccc";
      copyButton.style.padding = "5px 10px";
      copyButton.style.boxSizing = "border-box";
      copyButton.style.cursor = "pointer";
      copyButton.style.borderRadius = "5px";
      copyButton.style.fontSize = "12px";
      // 将复制按钮添加到代码块的父元素中
      preElement.appendChild(copyButton);
    },

    // 复制按钮
    copy(item, is_create_span = true) {
      let content = item;
      if (is_create_span) {
        // 创建一个隐藏的span 元素 将 标签去掉
        const span = document.createElement("span");
        span.innerHTML = item;
        span.style.display = "none";
        document.body.appendChild(span);
        content = span.innerText;
        document.body.removeChild(span);
      }

      // 创建一个隐藏的 textarea 元素
      const textarea = document.createElement("textarea");
      // 将需要复制的文本赋值给 textarea
      textarea.value = content;
      // 设置 textarea 为固定定位且透明度为 0，使其不可见
      textarea.style.position = "fixed";
      textarea.style.opacity = "0";
      // 将 textarea 添加到页面的 body 中
      document.body.appendChild(textarea);
      // 选中 textarea 中的文本
      textarea.select();
      try {
        // 执行复制命令
        const successful = document.execCommand("copy");
        if (successful) {
          this.$message.success("复制成功");
        } else {
          this.$message.error("复制失败");
        }
      } catch (err) {
        this.$message.error("复制失败");
      }
      // 复制完成后，将 textarea 从页面中移除
      document.body.removeChild(textarea);
    },

    // 滚动条到最底部
    setScrollToBottom() {
      this.$nextTick(() => {
        const scrollContainer = this.$refs.scrollContainer;
        if (scrollContainer) {
          scrollContainer.scrollTop = scrollContainer.scrollHeight;
        }
      });
    },

    // 建立与后端的链接
    async connectWebSocket() {
      console.log(this.userInfo, "xxxxxxxxxxxxxx");
      const result = await this.$connectWebSocket({ userId: this.userInfo.id });
      result.onmessage = (e) => {
        console.log(e.data);
        this.markdownText += e.data;

        const converter = new showdown.Converter();
        const length = this.history_messages.length - 1; // 获取当前索引
        this.history_messages[length].content = converter.makeHtml(
          this.markdownText
        );
        this.setScrollToBottom();
        this.highlightCode(true);
      };
    },
  },
};
</script>

<style scoped>
.main {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-direction: column;
  position: relative;
}

textarea:focus {
  outline: none;
}

/* 隐藏垂直滚动条 */
.chat::-webkit-scrollbar {
  width: 0;
}

/* 隐藏水平滚动条 */
.chat::-webkit-scrollbar {
  height: 0;
}

.chat .chatList {
  width: 100%;
  font-size: 14px;
  color: #333;
}

.chat .chatList .wen {
  float: right;
  width: 100%;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.chat .chatList .da {
  float: left;
  width: 100%;
  margin-bottom: 10px;
  position: relative;
}

.chat .chatList .wen .content,
.chat .chatList .da .content {
  padding: 10px;
  border-radius: 5px;
  display: inline-block;
}

.chat .chatList .da .content {
  background: #f1f3f5;
  position: relative;
}

.chat .chatList .wen .content {
  background: #a0ec70;
}

.chat-input textarea {
  width: 100%;
  flex: 1;
  border: none;
  background: #fff;
  padding: 20px;
  box-sizing: border-box;
  font-size: 14px;
  border-radius: 10px;
  border-bottom: 1px solid #f1f1f1;
}

.chat-input .btn {
  text-align: right;
  padding: 10px;
  box-sizing: border-box;
  height: 50px;
  width: 100%;
}

.suspension {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: top 0.5 linear !important;
}

.operation {
  width: 100%;
  height: 40px;
  border-bottom: 1px dashed #74c0fc;
  display: flex;
  align-items: center;
  margin-bottom: 10px;
  padding: 10px;
  box-sizing: border-box;
  cursor: pointer;
}

/* 当屏幕宽度小于等于600px时应用以下样式 */
@media screen and (max-width: 992px) {
  .chat {
    width: 100%;
    flex: 1;
    background: #fff;
    box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.3);
    padding: 10px;
    box-sizing: border-box;
    overflow-y: auto;
  }

  .chat-input {
    width: 100%;
    height: 180px;
    background: #fff;
    box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.3);
    border-radius: 10px;
    overflow: hidden;
    margin-top: 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-direction: column;
  }
}

/* 当屏幕宽度大于600px且小于等于900px时应用以下样式 */
@media screen and (min-width: 993px) {
  .main {
    width: 60%;
    margin: 0 auto;
  }

  .chat {
    width: 100%;
    flex: 1;
    background: #fff;
    padding: 10px;
    box-sizing: border-box;
    border-radius: 10px;
    overflow-y: auto;
  }

  .chat-input {
    width: 100%;
    height: 180px;
    background: #f3f4f6;
    border-radius: 10px;
    overflow: hidden;
    margin-top: 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-direction: column;
  }

  .chat-input textarea {
    background: #f3f4f6;
  }
}

pre {
  width: 100% !important;
  overflow-x: auto !important;
  /* 当内容在水平方向溢出时显示滚动条 */
  white-space: pre-wrap !important;
  /* 保留空白符序列，但是正常地进行换行 */
}
</style>
